home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 22 / Amiga Format AFCD22 (Jan 1998, Issue 106).iso / -in_the_mag- / emulation / dcmtoimg / dcmtoatr.c < prev    next >
C/C++ Source or Header  |  1997-11-17  |  10KB  |  431 lines

  1. /*
  2. ** dcmtoatr.c -- written by Chad Wagner
  3. **
  4. ** Revision History:
  5. ** 31 May 95  cmwagner@gate.net
  6. **  1 Jun 95  cmwagner@gate.net
  7. **            added in some portability macros from dcm.c
  8. **            added in read_atari16() function from dcm.c
  9. **            wrote write_atari16() function
  10. **            did a general clean-up of the code
  11. **  1 Jun 95  crow@cs.dartmouth.edu
  12. **            did a clean-up of the code, hopefully resolving any
  13. **            portability issues
  14. **  2 Jun 95  cmwagner@gate.net and crow@cs.dartmouth.edu
  15. **          Allow for multi-file DCM files, after they've been
  16. **          combined into a single file
  17. **  5 Jun 95  cmwagner@gate.net
  18. **            Fixed decoding routines to handle double density diskettes
  19. ** 30 Oct 97  willik@bellatlantic.net
  20. **          Added lines to allow compilation with DICE under AmigaDOS
  21. */
  22.  
  23. /* Include files */
  24. #include <stdio.h>
  25. #include <string.h>
  26.  
  27. /* prototypes */
  28. void decode_C1(void);
  29. void decode_C3(void);
  30. void decode_C4(void);
  31. void decode_C6(void);
  32. void decode_C7(void);
  33. void decode_FA_atr(void);
  34. int  read_atari16(FILE *);
  35. void write_atari16(FILE *,int);
  36. int  read_offset(FILE *);
  37. void read_sector(FILE *);
  38. void write_sector(FILE *);
  39.  
  40. /*
  41. ** Portability macros
  42. ** 1  Jun 95  crow@cs.dartmouth.edu (Preston Crow)
  43. */
  44. #if defined(__MSDOS) || defined(__MSDOS__) || defined(_MSDOS) || defined(_MSDOS_)
  45. #define MSDOS /* icky, icky, icky! */
  46. #endif
  47. #ifndef SEEK_SET
  48. #define SEEK_SET 0 /* May be missing from stdio.h */
  49. #endif
  50.  
  51. /* version of this program, as seen in usage message */
  52. #define VERSION "1.2"
  53.  
  54. /* this is used to calculate seek offsets */
  55. #ifndef _DCC
  56. #define SOFFSET ((((long)cursec - 1) * (cursec < 4 ? 128 : secsize)) + \
  57.                      16 - (cursec > 3 ? 384 : 0))
  58. #else
  59. #define SOFFSET ((((long)cursec - 1) * (cursec < 4 ? 128 : secsize)) + 16)
  60. #endif
  61.  
  62. /* Global variables */
  63. FILE        *fin,*fout;
  64. unsigned int    secsize;
  65. unsigned short    cursec=0,maxsec=0;
  66. unsigned char    createdisk=0,working=0,last=0,density,buf[256];
  67. int        doprint=1; /* True for diagnostic output */
  68.  
  69. /*
  70. ** main()
  71. */
  72. int main(int argc,char **argv)
  73. {
  74.     unsigned char    archivetype; /* Block type for first block */
  75.     unsigned char    blocktype; /* Current block type */
  76.     unsigned char    tmp; /* Temporary for read without clobber on eof */
  77.     unsigned char    imgin[256],imgout[256]; /* file names */
  78.     unsigned char    done=0; /* completion flag */
  79.     char        *self; /* program name from argv[0] */
  80.  
  81. #ifdef MSDOS
  82.     if ((self = strrchr(argv[0],'\\')) == NULL)
  83. #else
  84.     if ((self = strrchr(argv[0],'/')) == NULL)
  85. #endif
  86.       {
  87.           self = argv[0];
  88.       }
  89.     else
  90.       self++; /* Skip the slash */
  91.  
  92.     --argc;++argv; /* Don't look at the filename anymore */
  93.     /* Process switches */
  94.     if (argc) while (*argv[0]=='-') {
  95.         int nomore=0;
  96.  
  97.         ++argv[0]; /* skip the '-' */
  98.         while(*argv[0]) {
  99.             switch(*argv[0]) {
  100.                   case '-':
  101.                 nomore=1;
  102.                 break;
  103.                   case 'q':
  104.                   case 'Q':
  105.                 doprint = !doprint;
  106.                 break;
  107.                   default:
  108.                 fprintf(stderr,"Unsupported switch:  %c\n",*argv[0]);
  109.                 fprintf(stderr,"%s "VERSION" by cmwagner@gate.net\n",self);
  110.                 fprintf(stderr,"%s [-q] input[.dcm] [output[.atr]]\n",self);
  111.                 exit(1);
  112.             }
  113.             ++argv[0]; /* We've processed this flag */
  114.         }
  115.         --argc;++argv; /* Done processing these flags */
  116.         if(nomore) break; /* Filename may begin with '-' */
  117.     }
  118.  
  119.     if (argc<1 || argc>2) {
  120.         fprintf(stderr,"%s "VERSION" by cmwagner@gate.net\n",self);
  121.         fprintf(stderr,"%s [-q] input[.dcm] [output[.atr]]\n",self);
  122.         exit(1);
  123.     }
  124.  
  125.     strcpy(imgin,argv[0]);
  126.     if (strrchr(imgin,'.') == NULL)
  127.         strcat(imgin,".dcm");
  128.  
  129.     if (argc==2)
  130.         strcpy(imgout,argv[1]);
  131.     else {
  132.         char *p;
  133.  
  134.         strcpy(imgout,imgin);
  135.         if ((p = strrchr(imgout,'.')) != NULL)
  136.             *p = 0;
  137.     }
  138.     if (strrchr(imgout,'.') == NULL)
  139.         strcat(imgout,".atr");
  140.  
  141.     if ((fin = fopen(imgin,"rb")) == NULL) {
  142.         fprintf(stderr,"I couldn't open \"%s\" for reading.\n",imgin);
  143.         exit(1);
  144.     }
  145.  
  146.     archivetype = blocktype = fgetc(fin);
  147.     switch(blocktype) {
  148.         case 0xF9:
  149.         case 0xFA:
  150.             break;
  151.         default:
  152.             fprintf(stderr,"0x%02X is not a known header block.\n",blocktype);
  153.             exit(1);
  154.     }
  155.  
  156.     if ((fout = fopen(imgout,"rb")) != NULL) {
  157.         fprintf(stderr,"I can't use \"%s\" for output, it already exists.\n",imgout);
  158.         exit(1);
  159.     } else {
  160.         fout = fopen(imgout,"wb");
  161.     }
  162.  
  163.     rewind(fin);
  164.  
  165.     do {
  166.         if(doprint) printf("\rCurrent sector: %4u",cursec);
  167.  
  168. #ifdef MSDOS
  169.         if (kbhit()) {
  170.             if (getch() == 27) {
  171.                 fprintf(stderr,"  Processing terminated by user.\n");
  172.                 exit(1);
  173.             }
  174.         }
  175. #endif
  176.                 if (feof(fin)) {
  177.             fflush(stdout); /* Possible buffered I/O confusion fix */
  178.                         if ((!last) && (blocktype == 0x45) && (archivetype == 0xF9)) {
  179.                 fprintf(stderr,"\nMulti-part archive error.\n");
  180.                 fprintf(stderr,"To process these files, you must first combine the files into a single file.\n");
  181. #ifdef MSDOS
  182.                 fprintf(stderr,"\tCOPY /B file1.dcm+file2.dcm+file3.dcm newfile.dcm\n");
  183. #else
  184.                 fprintf(stderr,"\tcat file1.dcm file2.dcm file3.dcm > newfile.dcm\n");
  185. #endif
  186.                         }
  187.             else {
  188.                 fprintf(stderr,"  EOF before end block.\n");
  189.             }
  190.                         exit(1);
  191.                 }
  192. /*
  193.         if (working) {
  194.             if (((((long)cursec - 1) * secsize) + 16) != ftell(fout)) {
  195.                 fprintf(stderr,"  Output has desynched.\nfin=%lu fout=%lu != %lu "
  196.                 "cursec=%u secsize=%u\n",ftell(fin),ftell(fout),
  197.                 (((long)cursec - 1) * secsize) + 16,cursec,secsize);
  198.                 exit(1);
  199.             }
  200.         }
  201. */
  202.         tmp = fgetc(fin); /* blocktype is needed on EOF error--don't corrupt it */
  203.         if (feof(fin)) continue; /* Will abort on the check at the top of the loop */
  204.         blocktype = tmp;
  205.         switch(blocktype) {
  206.               case 0xF9:
  207.               case 0xFA:
  208.             /* New block */
  209.             decode_FA_atr();
  210.             break;
  211.               case 0x45:
  212.             /* End block */
  213.             working=0;
  214.             if (last) {
  215.                 if (doprint) printf("\r%s has been successfully decompressed.\n",imgout);
  216.                 fclose(fin);
  217.                 fclose(fout);
  218.                 done=1; /* Normal exit */
  219.             }
  220.             break;
  221.               case 0x41:
  222.               case 0xC1:
  223.             decode_C1();
  224.             break;
  225.               case 0x43:
  226.               case 0xC3:
  227.             decode_C3();
  228.             break;
  229.               case 0x44:
  230.               case 0xC4:
  231.             decode_C4();
  232.             break;
  233.               case 0x46:
  234.               case 0xC6:
  235.             decode_C6();
  236.             break;
  237.               case 0x47:
  238.               case 0xC7:
  239.             decode_C7();
  240.             break;
  241.               default:
  242.             fprintf(stderr,"\n\n0x%02X is not a known block type.  File may be "
  243.                 "corrupt.\n",blocktype);
  244.             exit(1);
  245.         } /* end case */
  246.  
  247.         if ((blocktype != 0x45) && (blocktype != 0xFA) &&
  248.         (blocktype != 0xF9)) {
  249.             if (!(blocktype & 0x80)) {
  250.                 cursec=read_atari16(fin);
  251.                 fseek(fout,SOFFSET,SEEK_SET);
  252.             } else {
  253.                 cursec++;
  254.             }
  255.         }
  256.     } while(!done); /* end do */
  257.     return(0); /* Should never be executed */
  258. }
  259.  
  260. void decode_C1(void)
  261. {
  262.     int    secoff,tmpoff,c;
  263.  
  264.     tmpoff=read_offset(fin);
  265.     c=fgetc(fin);
  266.     for (secoff=0; secoff<secsize; secoff++) {
  267.         buf[secoff]=c;
  268.     }
  269.     c=tmpoff;
  270.     for (secoff=0; secoff<tmpoff; secoff++) {
  271.         c--;
  272.         buf[c]=fgetc(fin);
  273.     }
  274.     write_sector(fout);
  275. }
  276.  
  277. void decode_C3(void)
  278. {
  279.     int    secoff,tmpoff,c;
  280.  
  281.     secoff=0;
  282.     do {
  283.         if (secoff)
  284.             tmpoff=read_offset(fin);
  285.         else
  286.             tmpoff=fgetc(fin);
  287.         for (; secoff<tmpoff; secoff++) {
  288.             buf[secoff]=fgetc(fin);
  289.         }
  290.         if (secoff == secsize)
  291.             break;
  292.         tmpoff=read_offset(fin);
  293.         c=fgetc(fin);
  294.         for (; secoff<tmpoff; secoff++) {
  295.             buf[secoff] = c;
  296.         }
  297.     } while(secoff < secsize);
  298.     write_sector(fout);
  299. }
  300.  
  301. void decode_C4(void)
  302. {
  303.     int    secoff,tmpoff;
  304.  
  305.     tmpoff=read_offset(fin);
  306.     for (secoff=tmpoff; secoff<secsize; secoff++) {
  307.         buf[secoff]=fgetc(fin);
  308.     }
  309.     write_sector(fout);
  310. }
  311.  
  312. void decode_C6(void)
  313. {
  314.     write_sector(fout);
  315. }
  316.  
  317. void decode_C7(void)
  318. {
  319.     read_sector(fin);
  320.     write_sector(fout);
  321. }
  322.  
  323. void decode_FA_atr(void)
  324. {
  325.     unsigned char c;
  326.  
  327.     if (working) {
  328.         fprintf(stderr,"\nTrying to start section but last section never had "
  329.         "an end section block.\n");
  330.         exit(1);
  331.     }
  332.     c=fgetc(fin);
  333.     density=((c & 0x70) >> 4);
  334.     last=((c & 0x80) >> 7);
  335.     switch(density) {
  336.           case 0:
  337.         maxsec=720;
  338.         secsize=128;
  339.         break;
  340.           case 2:
  341.         maxsec=720;
  342.         secsize=256;
  343.         break;
  344.           case 4:
  345.         maxsec=1040;
  346.         secsize=128;
  347.         break;
  348.           default:
  349.         fprintf(stderr,"  Density type is unknown, density type=%u\n",density);
  350.         exit(1);
  351.     }
  352.  
  353.     if (createdisk == 0) {
  354.         createdisk = 1;
  355.         /* write out atr header */
  356.         /* special code, 0x0296 */
  357.         write_atari16(fout,0x296);
  358.         /* image size (low) */
  359. #ifndef _DCC
  360.         write_atari16(fout,(short)(((long)maxsec * secsize) >> 4));
  361. #else
  362.         write_atari16(fout,maxsec);
  363. #endif
  364.         /* sector size */
  365.         write_atari16(fout,secsize);
  366.         /* image size (high) */
  367. #ifndef _DCC
  368.         write_atari16(fout,(short)(((long)maxsec * secsize) >> 20));
  369. #else
  370.         write_atari16(fout,0);
  371. #endif
  372.         /* 8 bytes unused */
  373.         write_atari16(fout,0);
  374.         write_atari16(fout,0);
  375.         write_atari16(fout,0);
  376.         write_atari16(fout,0);
  377.         memset(buf,0,256);
  378.         for (cursec=0; cursec<maxsec; cursec++) {
  379.             fwrite(buf,secsize,1,fout);
  380.         }
  381.     }
  382.     cursec=read_atari16(fin);
  383.     fseek(fout,SOFFSET,SEEK_SET);
  384.     working=1;
  385. }
  386.  
  387. /*
  388. ** read_atari16()
  389. ** Read a 16-bit integer with Atari byte-ordering.
  390. ** 1  Jun 95  crow@cs.dartmouth.edu (Preston Crow)
  391. */
  392. int read_atari16(FILE *fin)
  393. {
  394.     int ch_low,ch_high; /* fgetc() is type int, not char */
  395.  
  396.     ch_low = fgetc(fin);
  397.     ch_high = fgetc(fin);
  398.     return(ch_low + 256*ch_high);
  399. }
  400.  
  401. void write_atari16(FILE *fout,int n)
  402. {
  403.     unsigned char ch_low,ch_high;
  404.  
  405.     ch_low = (unsigned char)(n&0xff);
  406.     ch_high = (unsigned char)(n/256);
  407.     fputc(ch_low,fout);
  408.     fputc(ch_high,fout);
  409. }
  410.  
  411. int read_offset(FILE *fin)
  412. {
  413.     int ch; /* fgetc() is type int, not char */
  414.  
  415.     ch = fgetc(fin);
  416.     if (ch == 0)
  417.         ch = 256;
  418.  
  419.     return(ch);
  420. }
  421.  
  422. void read_sector(FILE *fin)
  423. {
  424.     fread(buf,(cursec < 4 ? 128 : secsize),1,fin);
  425. }
  426.  
  427. void write_sector(FILE *fout)
  428. {
  429.     fwrite(buf,(cursec < 4 ? 128 : secsize),1,fout);
  430. }
  431.